package com.gzz.orchid.common.webmvc.support.limiter.access;


import com.gzz.orchid.common.core.exception.BizzException;
import com.gzz.orchid.common.webmvc.support.limiter.OnLimitAspectCondition;
import com.gzz.orchid.common.webmvc.support.limiter.manager.ILimiterManager;
import com.gzz.orchid.common.webmvc.support.limiter.manager.Limiter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author higmd
 */
@Slf4j
@Aspect
//使用CGLIB代理
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Conditional(OnLimitAspectCondition.class)
public class AccessLimiterAspect {

    @Setter(onMethod_ = @Autowired)
    private ILimiterManager limiterManager;

    public AccessLimiterAspect() {
        log.info("启用限制访问 -- Access-Limiter-Aspect init");
    }

    /**
     * 拦截所有方法
     */
    @Pointcut("@annotation(com.gzz.orchid.common.webmvc.support.limiter.access.AccessLimiter)")
    private void limiterPoint() {

    }

    /**
     * 前置拦截
     */
    @Before("limiterPoint()")
    public void beforePoint(JoinPoint joinPoint) {
        log.info("限制访问拦截 -- Access-Limiter-Aspect before");
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        AccessLimiter limit = method.getAnnotation(AccessLimiter.class);
        if (Objects.nonNull(limit)) {
            Limiter limiter = Limiter.builder()
                    .limitNum(limit.limitNum())
                    .seconds(limit.seconds())
                    .key(limit.key())
                    .build();
            //
            if (!limiterManager.tryAccess(limiter)) {
                //throw new BizzException("There are currently many people , please try again later!");
                throw new BizzException("当前访问人数过多，请稍后再试！");
            }
        }
    }
}